package org.odefu.flash.display
{
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import starling.textures.Texture;

	public final class OdefuMovieClipFactory
	{
		public function OdefuMovieClipFactory()
		{
			throw new Error("OdefuMovieClipFactory is a static class!");
		}
		
		/**
		 * Creates a new Starling MovieClip from the Flash MovieClip.
		 * 
		 * @params:
		 *   mc: The Flash MovieClip which is converted to Starling MovieClip.
		 *   pivotX: The pivot's x coordinate for the MovieClip.
		 *   pivotY: The pivot's y coordinate for the MovieClip.
		 *   fps: The FPS of the MovieClip.
		 */
		public static function create(mc:MovieClip, fps:int = 12):OdefuMovieClip
		{
			const frameBoundsCache:FrameBoundsCache = new FrameBoundsCache(mc);
			const frameSize:Rectangle = calculateFrameSize(frameBoundsCache);
			const pivot:Point = getPivot(frameSize, mc);
			const textures:Vector.<Texture> = new Vector.<Texture>();
			const frameLabels:Array = new Array();
			drawFrames(mc, textures, frameLabels, frameSize, pivot);
			
			const omc:OdefuMovieClip = new OdefuMovieClip(textures, frameLabels, fps);
			omc.name = mc.name;
			omc.pivotX = Math.abs(pivot.x);
			omc.pivotY = Math.abs(pivot.y);
			return omc;
		}

		private static function getPivot(frameSize:Rectangle, mc:MovieClip):Point
		{
			mc.gotoAndStop(0);
			
			const filterBounds:Rectangle = new Rectangle();
			BoundsUtil.addFilterBounds(filterBounds, mc);
			
			return new Point(-frameSize.x - filterBounds.x, -frameSize.y - filterBounds.y);
		}
		
		private static function drawFrames(clip:MovieClip, textures:Vector.<Texture>, frameLabels:Array,
										   frameSize:Rectangle, pivot:Point):void
		{
			const bitmapData:BitmapData = new BitmapData(frameSize.width, frameSize.height, true, 0xFFFFFF);
			for (var i:int = 1; i <= clip.totalFrames; i++)
			{
				clip.gotoAndStop(i);
				textures.push(drawFrame(clip, frameSize, pivot, bitmapData));
				frameLabels.push(clip.currentFrameLabel);
			}
			bitmapData.dispose();
		}
		
		/**
		 * Draw the current frame from the MovieClip to a BitmapData and convert that to a Texture.
		 */
		private static function drawFrame(clip:MovieClip, frameSize:Rectangle, pivot:Point, bitmapData:BitmapData):Texture
		{
			// Clear the bitmapdata
			bitmapData.fillRect(bitmapData.rect, 0x00FFFFFF);
			
			const matrix:Matrix = clip.transform.matrix.clone();
			matrix.translate(pivot.x, pivot.y);
			
			bitmapData.draw(clip, matrix, clip.transform.colorTransform, null, null, true);
			
			return Texture.fromBitmapData(bitmapData, true, true);
		}

		/**
		 * Calculate the size needed to fit every frame.
		 */
		private static function calculateFrameSize(cache:FrameBoundsCache):Rectangle
		{
			const size:Rectangle = new Rectangle();
			for (var i:int = 0; i < cache.length; i++)
			{
				size.copyFrom(size.union(cache.get(i)));
			}
			return size;
		}
	}
}